package com.manong.config.security;

import com.manong.config.handler.AnonymousAuthenticationHandler;
import com.manong.config.handler.CustomerAccessDeniedHandler;
import com.manong.config.handler.LoginFailureHandler;
import com.manong.config.handler.LoginSuccessHandler;
import com.manong.config.security.Service.CustomerUserDetailsService;
import com.manong.config.security.filter.CheckTokenFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

/**
 * @author 李茂鑫
 * @Date 2025/1/13 16:15
 * @Descripition
 */
@Configuration
@EnableWebSecurity   //启用 Spring Security 功能，允许进行安全配置。
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启权限注解，默认是关闭的
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    //WebSecurityConfigurerAdapter是springsecurity提供的适配器类，通过继承它可以方便地进行自定义安全配置。
    @Resource //注入自定义的处理器和服务。
    protected LoginSuccessHandler loginSuccessHandler;
    //登录成功处理器
    @Resource
    protected LoginFailureHandler loginFailureHandler;
    //登录失败处理器
    @Resource
    protected AnonymousAuthenticationHandler anonymousAuthenticationHandler;
    //匿名用户未认证时的处理器
    @Resource
    protected CustomerAccessDeniedHandler customerAccessDeniedHandler;
    //自定义的拒绝访问处理器
    @Resource
    private CustomerUserDetailsService customerUserDetailsService;
    //自定义用户认证服务
    @Resource
    private CheckTokenFilter check;


    /**
     * 注入密码加密方式
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder(){

        return new BCryptPasswordEncoder();
    }

    /**
     * 处理登录认证
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http)throws Exception{
        http.addFilterBefore(check, UsernamePasswordAuthenticationFilter.class);
        //登录前进行过滤
        http.formLogin() //启用表单登录
                .loginProcessingUrl("/api/user/login")
                .successHandler(loginSuccessHandler)
                .failureHandler(loginFailureHandler)
                .usernameParameter("username")  //指定表带提交时的用户参数名称为username
                .and()
                .csrf()
                .disable()  //禁用CSRF防护，通常在开发RESTful API时禁用
                //CSRF（跨站请求伪造）用来防止跨站请求伪造攻击的，它通常用于 Web 应用，尤其是使用 Cookie 或 Session 来管理身份验证的情况。
                //RESTful API 通常使用 Token（如 JWT）进行身份验证，而不是依赖于传统的 Cookie 或 Session。
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //指定会话管理策略为无状态 (stateless)，即不使用 HTTP 会话来存储认证信息，适用于基于 Token 的认证。
                .and()
                .authorizeHttpRequests()
                .antMatchers("/api/user/login").permitAll()  //允许/api/user/login请求不需要认证
                .anyRequest().authenticated()   //其他所有请求都需要认证
                .and()
                .exceptionHandling()//异常时候
                .authenticationEntryPoint(anonymousAuthenticationHandler)//未认证时的处理方式
                .accessDeniedHandler(customerAccessDeniedHandler)//访问被拒绝时的处理方式
                .and()
                .cors(); //启用跨域请求支持
    }

    /**
     * 配置认证管理器
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth)throws Exception{
        auth.userDetailsService(customerUserDetailsService).passwordEncoder(passwordEncoder());
        //通过 AuthenticationManagerBuilder 配置自定义的用户认证服务 (customerUserDetailsService) 和密码加密方式 (passwordEncoder())。
    }

}
